package com.icss.train_sys_back.service.statistics_manage.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.icss.train_sys_back.entity.statistics_manage.PassengerFlowEntity;
import com.icss.train_sys_back.entity.statistics_manage.PassengerTrendEntity;
import com.icss.train_sys_back.entity.statistics_manage.PassengerTimeDistributionEntity;
import com.icss.train_sys_back.mapper.statistics_manage.PassengerStatisticsMapper;
import com.icss.train_sys_back.service.statistics_manage.PassengerStatisticsService;
import com.icss.train_sys_back.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author 小泽
 * @createTime 2025/10/10 9:23
 */
@Service
@Slf4j
public class PassengerStatisticsServiceImpl implements PassengerStatisticsService {
    @Autowired
    private PassengerStatisticsMapper passengerStatisticsMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private final ObjectMapper objectMapper = new ObjectMapper();

    //客流分析核心数据展示
    @Override
    public PassengerFlowEntity PassengerFlowSummary(String dateType, Integer stationId, String startDateStr, String endDateStr) {
        //时间范围类型（today/yesterday/week/month/year/custom）
        LocalDate startDate = DateUtil.stringToLocalDate(startDateStr);
        LocalDate endDate = DateUtil.stringToLocalDate(endDateStr);
        switch (dateType) {
            case "today":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                endDate = startDate.plusDays(1);
                break;
            case "yesterday":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            case "week":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 7);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            case "month":
                int monthValue = LocalDate.now().getMonthValue();
                startDate = LocalDate.of(LocalDate.now().getYear(), monthValue - 1, 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), 1);
                break;
            case "year":
                int year = LocalDate.now().getYear();
                startDate = LocalDate.of(year-1,  1, 1);
                endDate = LocalDate.of(year, 1, 1);
                break;
            case "custom":
                break;
        }

        // 设计Redis键
        String redisKey = String.format("passenger:summary:%s:%s:%s:%s",
                dateType,
                Objects.toString(stationId, "all"),
                startDate.toString(),
                endDate.toString());

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                PassengerFlowEntity result = objectMapper.readValue(cachedData, PassengerFlowEntity.class);
                log.info("从Redis缓存获取客流汇总数据");
                return result;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        //查询数据
        PassengerFlowEntity result = passengerStatisticsMapper.getPassengerFlowStatistics(startDate, endDate, stationId);

        // 将查询结果存入Redis
        try {
            if (result != null) {
                String jsonData = objectMapper.writeValueAsString(result);
                stringRedisTemplate.opsForValue().set(redisKey, jsonData, 30, TimeUnit.MINUTES);
                log.info("客流汇总数据已缓存到Redis");
            }
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return result;
    }

    //客流量趋势分析 - 增强空参数处理
    @Override
    public PassengerTrendEntity passengerTrend(String dateType, Integer stationId, String startDateStr, String endDateStr) {
        // 如果没有传入日期类型，则默认使用week
        if (dateType == null) {
            dateType = "week";
        }

        //时间范围类型（today/yesterday/week/month/year/custom）
        LocalDate startDate = DateUtil.stringToLocalDate(startDateStr);
        LocalDate endDate = DateUtil.stringToLocalDate(endDateStr);
        switch (dateType) {
            case "today":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                endDate = startDate.plusDays(1);
                break;
            case "yesterday":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            // 修改week为真正的本周（从周一开始到当前日期）
            case "week":
                LocalDate now = LocalDate.now();
                int dayOfWeek = now.getDayOfWeek().getValue();
                startDate = now.minusDays(dayOfWeek - 1); // 周一
                endDate = now.plusDays(1); // 明天（包含今天）
                break;

            // 修改month为本月数据
            case "month":
                int currentMonthValue = LocalDate.now().getMonthValue();
                startDate = LocalDate.of(LocalDate.now().getYear(), currentMonthValue, 1); // 本月1号
                endDate = LocalDate.now().plusDays(1); // 明天（包含今天）
                break;
            case "year":
                int year = LocalDate.now().getYear();
                // 修改为查询本年数据：从今年1月1日到当前日期
                startDate = LocalDate.of(year, 1, 1);      // 今年的1月1日
                endDate = LocalDate.now().plusDays(1);     // 明天（包含今天）
                break;
            case "custom":
                break;
        }

        // 设计Redis键
        String redisKey = String.format("passenger:trend:%s:%s:%s:%s",
                dateType,
                Objects.toString(stationId, "all"),
                startDate.toString(),
                endDate.toString());

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                PassengerTrendEntity result = objectMapper.readValue(cachedData, PassengerTrendEntity.class);
                log.info("从Redis缓存获取客流趋势数据");
                return result;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        //查询趋势数据
        List<Map<String, Object>> trendData = passengerStatisticsMapper.getPassengerTrendData(startDate, endDate, stationId);

        //构建返回结果
        PassengerTrendEntity result = new PassengerTrendEntity();
        List<String> xAxis = new ArrayList<>();
        List<Integer> totalFlow = new ArrayList<>();
        List<Integer> inFlow = new ArrayList<>();
        List<Integer> outFlow = new ArrayList<>();

        for (Map<String, Object> data : trendData) {
            //添加日期到x轴
            xAxis.add(data.get("date").toString());
            //添加各类客流量数据
            totalFlow.add(Integer.parseInt(data.get("totalFlow").toString()));
            inFlow.add(Integer.parseInt(data.get("inFlow").toString()));
            outFlow.add(Integer.parseInt(data.get("outFlow").toString()));
        }

        //设置返回实体的各字段
        result.setXAxis(xAxis);
        result.setTotalFlow(totalFlow);
        result.setInFlow(inFlow);
        result.setOutFlow(outFlow);

        // 将查询结果存入Redis
        try {
            String jsonData = objectMapper.writeValueAsString(result);
            stringRedisTemplate.opsForValue().set(redisKey, jsonData, 30, TimeUnit.MINUTES);
            log.info("客流趋势数据已缓存到Redis");
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return result;
    }

    //热门车站客流分布数据
    @Override
    public List<Map<String, Object>> getStationDistribution(String dateType, Integer stationId, String startDateStr, String endDateStr) {
        //时间范围类型（today/yesterday/week/month/year/custom）
        LocalDate startDate = DateUtil.stringToLocalDate(startDateStr);
        LocalDate endDate = DateUtil.stringToLocalDate(endDateStr);
        switch (dateType) {
            case "today":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                endDate = startDate.plusDays(1);
                break;
            case "yesterday":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            case "week":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 7);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            case "month":
                int monthValue = LocalDate.now().getMonthValue();
                startDate = LocalDate.of(LocalDate.now().getYear(), monthValue - 1, 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), 1);
                break;
            case "year":
                int year = LocalDate.now().getYear();
                startDate = LocalDate.of(year-1,  1, 1);
                endDate = LocalDate.of(year, 1, 1);
                break;
            case "custom":
                break;
        }

        // 设计Redis键
        String redisKey = String.format("passenger:station:%s:%s:%s:%s",
                dateType,
                Objects.toString(stationId, "all"),
                startDate.toString(),
                endDate.toString());

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                // 反序列化List<Map<String, Object>>
                List<Map<String, Object>> result = objectMapper.readValue(cachedData,
                    objectMapper.getTypeFactory().constructCollectionType(List.class,
                    objectMapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class)));
                log.info("从Redis缓存获取车站分布数据");
                return result;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        //调用Mapper查询车站分布数据
        List<Map<String, Object>> result = passengerStatisticsMapper.getStationDistributionData(startDate, endDate, stationId);

        // 将查询结果存入Redis
        try {
            String jsonData = objectMapper.writeValueAsString(result);
            stringRedisTemplate.opsForValue().set(redisKey, jsonData, 60, TimeUnit.MINUTES);
            log.info("车站分布数据已缓存到Redis");
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return result;
    }

    //客流量时段分布数据 - 根据时间跨度参数统计数据
    @Override
    public PassengerTimeDistributionEntity getPassengerTimeDistribution(String dateType, Integer stationId, String startDateStr, String endDateStr) {
        //时间范围类型（today/yesterday/week/month/year/custom）
        LocalDate startDate = DateUtil.stringToLocalDate(startDateStr);
        LocalDate endDate = DateUtil.stringToLocalDate(endDateStr);
        switch (dateType) {
            case "today":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                endDate = startDate.plusDays(1);
                break;
            case "yesterday":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            case "week":
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth() - 7);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                break;
            case "month":
                int monthValue = LocalDate.now().getMonthValue();
                startDate = LocalDate.of(LocalDate.now().getYear(), monthValue - 1, 1);
                endDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), 1);
                break;
            case "year":
                int year = LocalDate.now().getYear();
                startDate = LocalDate.of(year-1,  1, 1);
                endDate = LocalDate.of(year, 1, 1);
                break;
            case "custom":
                // 自定义日期范围，使用传入的参数
                break;
            default:
                // 默认使用当天数据
                startDate = LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonth(), LocalDate.now().getDayOfMonth());
                endDate = startDate.plusDays(1);
        }

        // 设计Redis键
        String redisKey = String.format("passenger:time:%s:%s:%s:%s",
                dateType,
                Objects.toString(stationId, "all"),
                startDate.toString(),
                endDate.toString());

        try {
            // 先查询redis中是否存在数据
            String cachedData = stringRedisTemplate.opsForValue().get(redisKey);
            if (!cachedData.isEmpty()) {
                PassengerTimeDistributionEntity result = objectMapper.readValue(cachedData, PassengerTimeDistributionEntity.class);
                log.info("从Redis缓存获取时段分布数据");
                return result;
            }
        } catch (Exception e) {
            log.error("Redis查询错误: {}", e.getMessage());
        }

        //查询时段分布数据
        List<Map<String, Object>> timeDistributionData = passengerStatisticsMapper.getPassengerTimeDistributionData(startDate, endDate, stationId);

        //构建返回结果
        PassengerTimeDistributionEntity result = new PassengerTimeDistributionEntity();
        List<String> xAxis = new ArrayList<>();
        List<Integer> flowData = new ArrayList<>();

        //预设所有时段
        String[] timeSlots = {
            "00:00-06:00", "06:00-09:00", "09:00-12:00",
            "12:00-15:00", "15:00-18:00", "18:00-21:00", "21:00-24:00"
        };

        //初始化所有时段的客流数据为0
        Map<String, Integer> slotDataMap = new HashMap<>();
        for (String slot : timeSlots) {
            slotDataMap.put(slot, 0);
        }

        //填充查询到的数据
        for (Map<String, Object> data : timeDistributionData) {
            String timeSlot = data.get("timeSlot").toString();
            Integer count = Integer.parseInt(data.get("count").toString());
            if (slotDataMap.containsKey(timeSlot)) {
                slotDataMap.put(timeSlot, count);
            }
        }

        //按顺序添加时段和对应的数据
        for (String slot : timeSlots) {
            xAxis.add(slot);
            flowData.add(slotDataMap.get(slot));
        }

        //设置返回实体的各字段
        result.setXAxis(xAxis);
        result.setFlowData(flowData);

        // 将查询结果存入Redis
        try {
            String jsonData = objectMapper.writeValueAsString(result);
            stringRedisTemplate.opsForValue().set(redisKey, jsonData, 30, TimeUnit.MINUTES);
            log.info("时段分布数据已缓存到Redis");
        } catch (Exception e) {
            log.error("Redis缓存写入错误: {}", e.getMessage());
        }

        return result;
    }

    //用于清除特定缓存（当需要强制刷新时使用）
    private void clearCache(String keyPattern) {
        try {
            Set<String> keys = stringRedisTemplate.keys(keyPattern);
            if (!keys.isEmpty()) {
                stringRedisTemplate.delete(keys);
                log.info("已清除缓存模式: {}, 共{}个键", keyPattern, keys.size());
            }
        } catch (Exception e) {
            log.error("清除缓存失败: {}", e.getMessage());
        }
    }

}

